I'm using a NASA API to render media images and info on a page. I want to add a button that "saves" the image to a favorites array. How would I do this? Right now, I have it so that when a button is clicked, the whole array is duplicated instead of a single object from the API.
import React, { useState, useEffect } from "react";
const apiKey = process.env.REACT_APP_APOD_KEY;
function Main() {
const [media, setMedia] = useState([]);
const [faves, setFaves] = useState([]);
const mediaGet = () => {
fetch(`https://api.nasa.gov/planetary/apod?api_key=${apiKey}&count=10`)
.then(res => res.json())
.then(result => {
setMedia(result)
})
}
const addFave = (media) => {
const newFavesList = [...faves, media];
setFaves(newFavesList);
// make this function add to faves array (new array)
};
useEffect(() => {
mediaGet()
}, [])
console.log(media);
return (
<>
<h1>Clever name here</h1>
{/* move this to Card component */}
{media.map((media) => (
<div key={media.id}>
<h2>{media.title}</h2>
<h3>{media.date}</h3>
<img src={media.url} alt={media.title} />
<button onClick={addFave} type="button">Add to array</button>
</div>
))}
</>
)
}
export default Main;
Your addFave function requires an argument (media) but you are calling it with onClick={addFave} which will only pass the click Event when called.
To pass the media object from your map callback, use
onClick={() => addFave(media)}
I would also change the handler to use the functional version of the useState setter
const addFave = (fave) => {
setFaves(prev => [...prev, fave])
}
FYI, try to avoid shadowing (re-using variable names in different scopes). There's even a handy ES-lint rule for this ~ https://eslint.org/docs/rules/no-shadow
{media.map(item => (
<div key={item.id}>
<h2>{item.title}</h2>
<h3>{item.date}</h3>
<img src={item.url} alt={item.title} />
<button onClick={() => addFave(item)} type="button">Add to array</button>
</div>
))}